home *** CD-ROM | disk | FTP | other *** search
- /*+-------------------------------------------------------------------------
- zmodem.c - ZMODEM protocol primitives
- based on code by Chuck Forsberg
- tip adaptation by wht%n4hgf@emory.mathcs.emory.edu
-
- Entry point Functions:
- zsbhdr(type,hdr) send binary header
- zshhdr(type,hdr) send hex header
- zgethdr(hdr,eflag) receive header - binary or hex
- zsdata(buf,len,frameend) send data
- zrdata(buf,len) receive data
- stohdr(pos) store position data in Txhdr
- long rclhdr(hdr) recover position offset from header
-
- Defined functions:
- noxrd7()
- rclhdr(hdr)
- stohdr(pos)
- zdlread()
- zgeth1()
- zgethdr(hdr,eflag)
- zgethex()
- zputhex(c)
- zrbhdr(hdr)
- zrbhdr32(hdr)
- zrdat32(buf,length)
- zrdata(buf,length)
- zrhhdr(hdr)
- zsbh32(hdr,type)
- zsbhdr(type,hdr)
- zsda32(buf,length,frameend)
- zsdata(buf,length,frameend)
- zsendline(c)
- zshhdr(type,hdr)
-
- --------------------------------------------------------------------------*/
- /*+:EDITS:*/
- /*:08-23-1990-13:48-wht@tridom-add mode 4 code */
- /*:05-21-1990-16:00-wht@tridom-adapt ecu xfer protocols for tipwht */
-
- #include "zmodem.h" /* wht */
- #include "zlint.h"
-
- extern char s128[]; /* wht */
- extern int Zctlesc; /* wht */
- extern int Zmodem; /* wht */
- extern long cr3tab[]; /* wht */
- extern unsigned Baudrate; /* wht */
- extern unsigned short crctab[]; /* wht */
-
- int Rxtimeout = 100; /* Tenths of seconds to wait for something */
-
- #if !defined(UNSL)
- #define UNSL
- #endif
-
-
-
- static lastsent; /* Last char we sent */
- static evenp; /* Even parity seen on header */
-
- /* Globals used by ZMODEM functions */
- char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
- char Rxhdr[4]; /* Received header */
- char Txhdr[4]; /* Transmitted header */
- int Crc32; /* Display flag indicating 32 bit CRC being received */
- int Crc32t; /* Display flag indicating 32 bit CRC being sent */
- int Rxcount; /* Count of data bytes received */
- int Rxframeind; /* ZBIN ZBIN32,or ZHEX type of frame received */
- int Rxtimeout; /* Tenths of seconds to wait for something */
- int Rxtype; /* Type of header received */
- int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
- int Zrwindow; /* RX window size (controls garbage count) */
- long Rxpos; /* Received file position */
- long Txpos; /* Transmitted file position */
-
- char *frametypes[] =
- {
- "Carrier Lost", /* -3 */
- "TIMEOUT", /* -2 */
- "ERROR", /* -1 */
- /* #define FTOFFSET 3 moved to zmodem.h */
- "ZRQINIT",
- "ZRINIT",
- "ZSINIT",
- "ZACK ",
- "ZFILE",
- "ZSKIP",
- "ZNAK ",
- "ZABORT",
- "ZFIN ",
- "ZRPOS",
- "ZDATA",
- "ZEOF ",
- "ZFERR",
- "ZCRC ",
- "ZCHALLENGE",
- "ZCOMPL",
- "ZCAN ",
- "ZFREECNT",
- "ZCOMMAND",
- "ZSTDERR",
- "xxxxx"
- #define FRTYPES 22 /* Total number of frame types in this array */
- /* not including psuedo negative entries */
- };
-
- static char masked[] = "8 bit transparent path required";
- static char badcrc[] = "Bad CRC";
-
- /* Send ZMODEM binary header hdr of type type */
- zsbhdr(type,hdr)
- register unsigned char *hdr;
- {
- register int n;
- register unsigned crc;
-
- report_tx_ind(1);
- sprintf(s128,"hdr %s %ld",frametypes[type+FTOFFSET],rclhdr(hdr));
- report_last_txhdr(s128,0);
-
- xsendline(ZPAD);
- xsendline(ZDLE);
-
- if(Crc32t=Txfcs32)
- zsbh32(hdr,type);
- else
- {
- xsendline(ZBIN);
- zsendline(type);
- crc = updcrc(type,0);
-
- for(n=4; --n >= 0; ++hdr)
- {
- zsendline(*hdr);
- crc = updcrc(*hdr,crc);
- }
- crc = updcrc(0,updcrc(0,crc));
- zsendline(crc>>8);
- zsendline(crc);
- }
- if(type != ZDATA)
- flushline();
- mode(4);
- report_tx_ind(0);
- }
-
-
- /* Send ZMODEM binary header hdr of type type */
- zsbh32(hdr,type)
- register char *hdr;
- {
- register int n;
- register UNSL long crc;
-
- report_tx_ind(1);
- xsendline(ZBIN32);
- zsendline(type);
- crc = 0xFFFFFFFFL;
- crc = UPDC32(type,crc);
-
- for(n=4; --n >= 0; ++hdr)
- {
- crc = UPDC32((0377 & *hdr),crc);
- zsendline(*hdr);
- }
- crc = ~crc;
- for(n=4; --n >= 0;)
- {
- zsendline((int)crc);
- crc >>= 8;
- }
- mode(4);
- report_tx_ind(0);
- }
-
- /* Send ZMODEM HEX header hdr of type type */
- zshhdr(type,hdr)
- register unsigned char *hdr;
- {
- register int n;
- register unsigned short crc;
-
- report_tx_ind(1);
-
- sprintf(s128,"hdr %s %ld",frametypes[type+FTOFFSET],rclhdr(hdr));
- report_last_txhdr(s128,0);
- sendline(ZPAD);
- sendline(ZPAD);
- sendline(ZDLE);
- sendline(ZHEX);
- zputhex(type);
- Crc32t = 0;
-
- crc = updcrc(type,0);
- for(n=4; --n >= 0; ++hdr)
- {
- zputhex(*hdr);
- crc = updcrc(*hdr,crc);
- /* crc = updcrc((0377 & *hdr),crc); original - wht */
- }
- crc = updcrc(0,updcrc(0,crc));
- zputhex(crc>>8);
- zputhex(crc);
-
- /* Make it printable on remote machine */
- sendline(015);
- sendline(012);
- /*
- * Uncork the remote in case a fake XOFF has stopped data flow
- */
- if(type != ZFIN && type != ZACK)
- sendline(021);
- flushline();
- mode(4);
- report_tx_ind(0);
- }
-
- /*
- * Send binary array buf of length length,with ending ZDLE sequence frameend
- */
- static char *Zendnames[] = { "ZCRCE","ZCRCG","ZCRCQ","ZCRCW"};
-
- zsdata(buf,length,frameend)
- register unsigned char *buf;
- {
- register unsigned short crc;
-
- report_tx_ind(1);
-
- sprintf(s128,"data %s %d bytes",Zendnames[frameend-ZCRCE&3],length);
- report_last_txhdr(s128,0);
- if(Crc32t)
- zsda32(buf,length,frameend);
- else
- {
- crc = 0;
- for(;--length >= 0; ++buf)
- {
- zsendline(*buf);
- crc = updcrc(*buf,crc);
- }
- xsendline(ZDLE);
- xsendline(frameend);
- crc = updcrc(frameend,crc);
-
- crc = updcrc(0,updcrc(0,crc));
- zsendline(crc>>8);
- zsendline(crc);
- }
- if(frameend == ZCRCW)
- {
- xsendline(XON);
- flushline();
- }
- mode(4);
- report_tx_ind(0);
-
- }
-
- zsda32(buf,length,frameend)
- register char *buf;
- {
- register int c;
- register UNSL long crc;
-
- report_tx_ind(1);
-
- crc = 0xFFFFFFFFL;
- for(;--length >= 0; ++buf)
- {
- c = *buf & 0377;
- if(c & 0140)
- xsendline(lastsent = c);
- else
- zsendline(c);
- crc = UPDC32(c,crc);
- }
- xsendline(ZDLE);
- xsendline(frameend);
- crc = UPDC32(frameend,crc);
-
- crc = ~crc;
- for(length=4; --length >= 0;)
- {
- zsendline((int)crc);
- crc >>= 8;
- }
- mode(4);
- report_tx_ind(0);
- }
-
- /*
- * Receive array buf of max length with ending ZDLE sequence
- * and CRC. Returns the ending character or error code.
- * NB: On errors may store length+1 bytes!
- */
- zrdata(buf,length)
- register char *buf;
- {
- register int c;
- register unsigned short crc;
- register char *end;
- register int d;
-
- report_rx_ind(1);
-
- if(Rxframeind == ZBIN32)
- {
- report_rx_ind(0);
- return(zrdat32(buf,length));
- }
-
- crc = Rxcount = 0;
- end = buf + length;
- while(buf <= end)
- {
- if((c = zdlread()) & ~0377)
- {
- crcfoo:
- switch(c)
- {
- case GOTCRCE:
- case GOTCRCG:
- case GOTCRCQ:
- case GOTCRCW:
- crc = updcrc(((d=c)&0377),crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = updcrc(c,crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = updcrc(c,crc);
- if(crc & 0xFFFF)
- {
- report_str(badcrc,0);
- report_rx_ind(0);
- return(ERROR);
- }
- Rxcount = length - (end - buf);
- report_rxblklen(Rxcount);
- sprintf(s128,"data %s %d bytes",
- Zendnames[d-GOTCRCE&3],Rxcount);
- report_last_rxhdr(s128,0);
- report_rx_ind(0);
- return(d);
- case GOTCAN:
- report_str("Sender Cancelled",1);
- report_rx_ind(0);
- return(ZCAN);
- case TIMEOUT:
- report_str("TIMEOUT",1);
- report_rx_ind(0);
- return(c);
- default:
- report_str("Bad data subpacket",1);
- report_rx_ind(0);
- return(c);
- }
- }
- *buf++ = c;
- crc = updcrc(c,crc);
- }
- report_str("Data subpacket too long",1);
- report_rx_ind(0);
- return(ERROR);
- }
-
- zrdat32(buf,length)
- register char *buf;
- {
- register int c;
- register UNSL long crc;
- register char *end;
- register int d;
-
- report_rx_ind(1);
- crc = 0xFFFFFFFFL;
- Rxcount = 0;
- end = buf + length;
- while(buf <= end)
- {
- if((c = zdlread()) & ~0377)
- {
- crcfoo:
- switch(c)
- {
- case GOTCRCE:
- case GOTCRCG:
- case GOTCRCQ:
- case GOTCRCW:
- d = c;
- c &= 0377;
- crc = UPDC32(c,crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = UPDC32(c,crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = UPDC32(c,crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = UPDC32(c,crc);
- if((c = zdlread()) & ~0377)
- goto crcfoo;
- crc = UPDC32(c,crc);
- if(crc != 0xDEBB20E3)
- {
- report_str(badcrc,0);
- report_rx_ind(0);
- return(ERROR);
- }
- Rxcount = length - (end - buf);
- report_rxblklen(Rxcount);
- sprintf(s128,"data %s %d bytes",
- Zendnames[d-GOTCRCE&3],Rxcount);
- report_last_rxhdr(s128,0);
- report_rx_ind(0);
- return(d);
- case GOTCAN:
- report_str("Sender Canceled",1);
- report_rx_ind(0);
- return(ZCAN);
- case TIMEOUT:
- report_str("TIMEOUT",1);
- report_rx_ind(0);
- return(c);
- default:
- report_str("Bad data subpacket",1);
- report_rx_ind(0);
- return(c);
- }
- }
- *buf++ = c;
- crc = UPDC32(c,crc);
- }
- report_str("Data subpacket too long",1);
- report_rx_ind(0);
- return(ERROR);
- }
-
-
- /*
- * Read a ZMODEM header to hdr,either binary or hex.
- * eflag controls local display of non zmodem characters:
- * 0: no display
- * 1: display printing characters only
- * 2: display all non ZMODEM characters
- * On success,set Zmodem to 1,set Rxpos and return type of header.
- * Otherwise return negative on error.
- * Return ERROR instantly if ZCRCW sequence,for fast error recovery.
- */
- zgethdr(hdr,eflag)
- char *hdr;
- {
- register int c,n,cancount;
-
- report_rx_ind(1);
- n = Zrwindow + Baudrate; /* Max bytes before start of frame */
- Rxframeind = Rxtype = 0;
-
- startover:
- cancount = 5;
- again:
- /* Return immediate ERROR if ZCRCW sequence seen */
- switch(c = readline(Rxtimeout))
- {
- case RCDO:
- case TIMEOUT:
- goto fifi;
- case CAN:
- gotcan:
- if(--cancount <= 0)
- {
- c = ZCAN;
- goto fifi;
- }
- switch(c = readline(1))
- {
- case TIMEOUT:
- goto again;
- case ZCRCW:
- c = ERROR;
- /* **** FALL THRU TO **** */
- case RCDO:
- goto fifi;
- default:
- break;
- case CAN:
- if(--cancount <= 0)
- {
- c = ZCAN;
- goto fifi;
- }
- goto again;
- }
- /* **** FALL THRU TO **** */
- default:
- agn2:
- if( --n == 0)
- {
- report_str("Garbage count exceeded",1);
- report_last_rxhdr("Noise",0);
- report_rx_ind(0);
- return(ERROR);
- }
- goto startover;
- case ZPAD|0200: /* This is what we want. */
- case ZPAD: /* This is what we want. */
- evenp = c & 0200;
- break;
- }
- cancount = 5;
- splat:
- switch(c = noxrd7())
- {
- case ZPAD:
- goto splat;
- case RCDO:
- case TIMEOUT:
- goto fifi;
- default:
- goto agn2;
- case ZDLE: /* This is what we want. */
- break;
- }
-
- switch(c = noxrd7())
- {
- case RCDO:
- case TIMEOUT:
- goto fifi;
- case ZBIN:
- Rxframeind = ZBIN;
- Crc32 = FALSE;
- c = zrbhdr(hdr);
- break;
- case ZBIN32:
- Crc32 = Rxframeind = ZBIN32;
- c = zrbhdr32(hdr);
- break;
- case ZHEX:
- Rxframeind = ZHEX;
- Crc32 = FALSE;
- c = zrhhdr(hdr);
- break;
- case CAN:
- goto gotcan;
- default:
- goto agn2;
- }
- Rxpos = hdr[ZP3] & 0377;
- Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
- Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
- Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
- fifi:
- switch(c)
- {
- case GOTCAN:
- c = ZCAN;
- /* **** FALL THRU TO **** */
- case ZNAK:
- case ZCAN:
- case ERROR:
- case TIMEOUT:
- case RCDO:
- sprintf(s128,"Got %s",frametypes[c+FTOFFSET]);
- report_str(s128,1);
- /* **** FALL THRU TO **** */
- default:
- if(c >= -3 && c <= FRTYPES)
- sprintf(s128,"hdr %s %ld",frametypes[c+FTOFFSET],Rxpos);
- else
- sprintf(s128,"hdr 0x%02x? %ld",c,Rxpos);
- report_last_rxhdr(s128,0);
- }
- report_rx_ind(0);
- return(c);
- }
-
- /* Receive a binary style header (type and position) */
- zrbhdr(hdr)
- register char *hdr;
- {
- register int c,n;
- register unsigned short crc;
-
- if((c = zdlread()) & ~0377)
- return(c);
- Rxtype = c;
- crc = updcrc(c,0);
-
- for(n=4; --n >= 0; ++hdr)
- {
- if((c = zdlread()) & ~0377)
- return(c);
- crc = updcrc(c,crc);
- *hdr = c;
- }
- if((c = zdlread()) & ~0377)
- return(c);
- crc = updcrc(c,crc);
- if((c = zdlread()) & ~0377)
- return(c);
- crc = updcrc(c,crc);
- if(crc & 0xFFFF)
- {
- if(evenp)
- report_str(masked,1);
- report_str(badcrc,0);
- return(ERROR);
- }
- #if defined(ZMODEM)
- Protocol = ZMODEM;
- #endif
- Zmodem = 1;
- return(Rxtype);
- }
-
- /* Receive a binary style header (type and position) with 32 bit FCS */
- zrbhdr32(hdr)
- register char *hdr;
- {
- register int c,n;
- register UNSL long crc;
-
- if((c = zdlread()) & ~0377)
- return(c);
- Rxtype = c;
- crc = 0xFFFFFFFFL;
- crc = UPDC32(c,crc);
-
- for(n=4; --n >= 0; ++hdr)
- {
- if((c = zdlread()) & ~0377)
- return(c);
- crc = UPDC32(c,crc);
- *hdr = c;
- }
- for(n=4; --n >= 0;)
- {
- if((c = zdlread()) & ~0377)
- return(c);
- crc = UPDC32(c,crc);
- }
- if(crc != 0xDEBB20E3)
- {
- if(evenp)
- report_str(masked,1);
- report_str(badcrc,0);
- return(ERROR);
- }
- #if defined(ZMODEM)
- Protocol = ZMODEM;
- #endif
- Zmodem = 1;
- return(Rxtype);
- }
-
-
- /* Receive a hex style header (type and position) */
- zrhhdr(hdr)
- char *hdr;
- {
- register int c;
- register unsigned short crc;
- register int n;
-
- if((c = zgethex()) < 0)
- return(c);
- Rxtype = c;
- crc = updcrc(c,0);
-
- for(n=4; --n >= 0; ++hdr)
- {
- if((c = zgethex()) < 0)
- return(c);
- crc = updcrc(c,crc);
- *hdr = c;
- }
- if((c = zgethex()) < 0)
- return(c);
- crc = updcrc(c,crc);
- if((c = zgethex()) < 0)
- return(c);
- crc = updcrc(c,crc);
- if(crc & 0xFFFF)
- {
- report_str(badcrc,0);
- return(ERROR);
- }
- if(readline(1) == '\r') /* Throw away possible cr/lf */
- readline(1);
- #if defined(ZMODEM)
- Protocol = ZMODEM;
- #endif
- Zmodem = 1;
- return(Rxtype);
- }
-
- /* Send a byte as two hex digits */
- zputhex(c)
- register int c;
- {
- static char digits[] = "0123456789abcdef";
-
- sendline(digits[(c&0xF0)>>4]);
- sendline(digits[(c)&0xF]);
- }
-
- /*
- * Send character c with ZMODEM escape sequence encoding.
- * Escape XON,XOFF. Escape CR following @ (Telenet net escape)
- */
- zsendline(c)
- {
-
- /* Quick check for non control characters */
- if(c & 0140)
- xsendline(lastsent = c);
- else
- {
- switch(c &= 0377)
- {
- case ZDLE:
- xsendline(ZDLE);
- xsendline(lastsent = (c ^= 0100));
- break;
- case 015:
- case 0215:
- if(!Zctlesc && (lastsent & 0177) != '@')
- goto sendit;
- /* **** FALL THRU TO **** */
- case 020:
- case 021:
- case 023:
- case 0220:
- case 0221:
- case 0223:
- xsendline(ZDLE);
- c ^= 0100;
- sendit:
- xsendline(lastsent = c);
- break;
- default:
- if(Zctlesc && ! (c & 0140))
- {
- xsendline(ZDLE);
- c ^= 0100;
- }
- xsendline(lastsent = c);
- }
- }
- }
-
- /* Decode two lower case hex digits into an 8 bit byte value */
- zgethex()
- {
- register int c;
-
- c = zgeth1();
- return(c);
- }
- zgeth1()
- {
- register int c,n;
-
- if((c = noxrd7()) < 0)
- return(c);
- n = c - '0';
- if(n > 9)
- n -= ('a' - ':');
- if(n & ~0xF)
- return(ERROR);
- if((c = noxrd7()) < 0)
- return(c);
- c -= '0';
- if(c > 9)
- c -= ('a' - ':');
- if(c & ~0xF)
- return(ERROR);
- c += (n<<4);
- return(c);
- }
-
- /*
- * Read a byte,checking for ZMODEM escape encoding
- * including CAN*5 which represents a quick abort
- */
- zdlread()
- {
- register int c;
-
- again:
- /* Quick check for non control characters */
- if((c = readline(Rxtimeout)) & 0140)
- return(c);
- switch(c)
- {
- case ZDLE:
- break;
- case 023:
- case 0223:
- case 021:
- case 0221:
- goto again;
- default:
- if(Zctlesc && !(c & 0140))
- {
- goto again;
- }
- return(c);
- }
- again2:
- if((c = readline(Rxtimeout)) < 0)
- return(c);
- if(c == CAN && (c = readline(Rxtimeout)) < 0)
- return(c);
- if(c == CAN && (c = readline(Rxtimeout)) < 0)
- return(c);
- if(c == CAN && (c = readline(Rxtimeout)) < 0)
- return(c);
- switch(c)
- {
- case CAN:
- return(GOTCAN);
- case ZCRCE:
- case ZCRCG:
- case ZCRCQ:
- case ZCRCW:
- return(c | GOTOR);
- case ZRUB0:
- return(0177);
- case ZRUB1:
- return(0377);
- case 023:
- case 0223:
- case 021:
- case 0221:
- goto again2;
- default:
- if(Zctlesc && ! (c & 0140))
- {
- goto again2;
- }
- if((c & 0140) == 0100)
- return(c ^ 0100);
- break;
- }
- sprintf(s128,"Bad escape sequence %x",c);
- report_str(s128,1);
- return(ERROR);
- }
-
- /*
- * Read a character from the modem line with timeout.
- * Eat parity,XON and XOFF characters.
- */
- noxrd7()
- {
- register int c;
-
- for(;;)
- {
- if((c = readline(Rxtimeout)) < 0)
- return(c);
- switch(c &= 0177)
- {
- case XON:
- case XOFF:
- continue;
- default:
- if(Zctlesc && !(c & 0140))
- continue;
- case '\r':
- case '\n':
- case ZDLE:
- return(c);
- }
- }
- }
-
- /* Store long integer pos in Txhdr */
- stohdr(pos)
- long pos;
- {
- Txhdr[ZP0] = pos;
- Txhdr[ZP1] = pos>>8;
- Txhdr[ZP2] = pos>>16;
- Txhdr[ZP3] = pos>>24;
- }
-
- /* Recover a long integer from a header */
- long
- rclhdr(hdr)
- register char *hdr;
- {
- register long l;
-
- l = (hdr[ZP3] & 0377);
- l = (l << 8) | (hdr[ZP2] & 0377);
- l = (l << 8) | (hdr[ZP1] & 0377);
- l = (l << 8) | (hdr[ZP0] & 0377);
- return(l);
- }
-
- /* end of zmodem.c */
- /* vi: set tabstop=4 shiftwidth=4: */
-